//
//  LBRadianGradientTextureFilter.mm
//  OpenGLGame
//
//  Created by Nguyen Cong Huy on 12/13/12.
//  Copyright (c) 2012 UIT. All rights reserved.
//

#include <iostream>
#include "LBRadialGradientTextureFilter.h"
#include "LBGraphics.h"

char radialGradientTextureFilterFragStr[] = ""
"precision highp float;"

"varying highp vec2 vtexCoor;"
"varying highp vec2 vtexCoor2;"

"uniform sampler2D texture;"
"uniform sampler2D texture2; "

"varying vec4 vposition;"

"uniform float opacity;"
"uniform int blendType;"


// soft light function (opacity equal 1/2 value in photoshop)
"vec4 softLight(vec4 base, vec4 blend, float opacity){"
"   vec4 white = vec4(1.0, 1.0, 1.0, 1.0);"
"   vec4 lumCoeff = vec4(0.2125, 0.7154, 0.0721, 1.0);"
"   vec4 result;"

"   float luminance = dot(base, lumCoeff);"
"   if (luminance < 0.45)"
"       result = 2.0 * blend * base;"
"   else if (luminance > 0.55)"
"       result = white - 2.0 * (white - blend) * (white - base);"
"   else"
"   {"
"       vec4 result1 = 2.0 * blend * base;"
"       vec4 result2 = white - 2.0 * (white - blend) * (white - base);"
"       result = mix(result1, result2, (luminance - 0.45) * 10.0);"
"   }"
"    result = mix(base, result, opacity);"
"   return result;"
"}"
// END soft light function

// linear light function
"vec4 linearLight(vec4 base, vec4 blend, float opacity){"
"   vec4 result = base;"
"   if (blend.r > 0.5) result.r = base.r + 2.0*(blend.r-0.5);"
"   else result.r = base.r + 2.0*blend.r - 1.0;"
"   if (blend.g > 0.5) result.g = base.g + 2.0*(blend.g-0.5);"
"   else result.g = base.r + 2.0*blend.r - 1.0;"
"   if (blend.r > 0.5) result.b = base.r + 2.0*(blend.r-0.5);"
"   else result.b = base.r + 2.0*blend.r - 1.0;"
"   result = mix(base, result, opacity);"
"   result = clamp(result, 0.0, 1.0);"
"   return result;"
"}"
// END linear light function

// overlay function
"vec4 overlay(vec4 base, vec4 blend, float opacity){"
"   vec4 white = vec4(1.0, 1.0, 1.0, 1.0);"
"   vec4 lumCoeff = vec4(0.2125, 0.7154, 0.0721, 1.0);"
"   float luminance = dot(base, lumCoeff);"
"   vec4 result;"
"   if (luminance < 0.45)"
"       result = 2.0 * blend * base;"
"   else if (luminance > 0.55)"
"       result = white - 2.0 * (white - blend) * (white - base);"
"   else"
"   {"
"       vec4 result1 = 2.0 * blend * base;"
"       vec4 result2 = white - 2.0 * (white - blend) * (white - base);"
"       result = mix(result1, result2, (luminance - 0.45) * 10.0);"
"   }"
"   result = mix(base, result, opacity);"
"   return result;"
"}"
// END overlay function

// hard light blend function
"vec4 hardLight(vec4 base, vec4 blend, float opacity){"
"   vec4 result =  base;"
"    if (blend.r > 0.5) result.r = 1.0 - (1.0-base.r) *(1.0-2.0*(blend.r-0.5));"
"    else result.r = base.r * (2.0*blend.r);"

"    if (blend.g > 0.5) result.g = 1.0 - (1.0-base.g) *(1.0-2.0*(blend.g-0.5));"
"    else result.g = base.g * (2.0*blend.g);"

"    if (blend.b > 0.5) result.b = 1.0 - (1.0-base.b) *(1.0-2.0*(blend.b-0.5));"
"    else result.b = base.b * (2.0*blend.b);"

"    result = mix(base, result, opacity);"
"    return result;"
"}"
// END hard light blend function

"void main()"
"{"
"   lowp vec4 textureColor = texture2D(texture, vtexCoor);"
"   lowp vec4 texture2Color = texture2D(texture2, vtexCoor2);"
"   lowp vec4 result;"
"   if(blendType == 0) result = softLight(textureColor, texture2Color, opacity);"
"   else if (blendType == 1) result = linearLight(textureColor, texture2Color, opacity);"
"   else if (blendType == 2) result = hardLight(textureColor, texture2Color, opacity);"
"   else if (blendType == 3) result = overlay(textureColor, texture2Color, opacity);"
"    gl_FragColor = result;"
"}"
;



LBRadialGradientTextureFilter::LBRadialGradientTextureFilter(){
    init(0, radialGradientTextureFilterFragStr);
    opacityUniform = program->uniformIndex("opacity");
    blendTypeUniform = program->uniformIndex("blendType");
    setOpacity(1.0f);
}

void LBRadialGradientTextureFilter::setOpacity(float opacity){
    this->opacity = opacity;
    LBGraphics::getInstance()->useProgram(program);
    glUniform1f(opacityUniform, opacity);
}

void LBRadialGradientTextureFilter::setBlendTexture(LBTexture* blendTexture){
    setTexture2(blendTexture);
}

void LBRadialGradientTextureFilter::setBlendType(int blendType){
    this->blendType = blendType;
    LBGraphics::getInstance()->useProgram(program);
    glUniform1i(blendTypeUniform, blendType);
}